﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Data;
using log4net;

namespace Net
{
    public delegate void BoolCallback(bool boolResult);
    public delegate void UpdateInfoCallback(string[] udpateFileName, int[] udpateFileLength);
    public delegate void UpdateDataReachCallback(int index, int length);
    public delegate void IntCallback(int i);
    public delegate void StringCallback(string str);
    public delegate void DataSetCallback(DataSet ds);
    public delegate void DataTableCallback(DataTable dt);

    public class NetService
    {
        internal static Net net = new Net();

        internal static IDictionary<byte, NetCallback> callbackMap = new Dictionary<byte, NetCallback>();

        public static event StringCallback OutLine;
		
		private static ILog log = LogManager.GetLogger(typeof(NetService).Name);

        internal void ProcessOutLine(string str)
        {
            OutLine(str);
        }

        public NetService()
        {
            
        }

        /// <summary>
        /// 返回连接状态
        /// </summary>
        /// <returns>true表示连接正常，false表示未连接</returns>
        public bool IsConnected()
        {
            bool connectState = net.IsConnect();
			log.Info(connectState ? "已连接" : "未连接");
            return connectState;
        }

        /// <summary>
        /// 连接到服务器
        /// </summary>
        /// <param name="IP">远程服务器IP</param>
        /// <param name="port">远程服务器端口</param>
        /// <returns>如果连接成功则返回true</returns>
        public bool Connect(string ipAddress, int port)
        {
			bool connectState = net.Connect(ipAddress, port);
			log.Info(connectState ? "连接成功" : "连接失败");
            return connectState;
        }

        
        /// <summary>
        /// 向服务器发送本地客户端版本，询问是否要更新
        /// </summary>
        /// <param name="clientVersion">客户端的版本号</param>
        /// <returns>true表示客户端版本较低，false表示为最新版本无需更新</returns>
        public bool IsNeedUpdate(int clientVersion)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            netCallback.AsyncObject = false;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1020", clientVersion.ToString());
            netCallback.DataReach.WaitOne(3000);
            return (bool)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向服务器异敊发送本地客户端版本，询问是否要更新，有结果时调用回调的委托实例
        /// </summary>
        /// <param name="clientVersion">客户端的版本号</param>
        /// <param name="boolCallback">有结果时异步调用此委托实例</param>
        public void IsNeedUpdate(int clientVersion, BoolCallback boolCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.boolCallback = boolCallback;
            netCallback.State = NetCallback.WaitBoolCallback;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1020", clientVersion.ToString());
        }

        /// <summary>
        /// 向服务器发送本地客户端版本，请求更新
        /// </summary>
        /// <param name="clientVersion">客户端的版本号</param>
        /// <param name="updateInfoCallback">如果有更新的话调用此回调函数返回更新文件的信息，如果不需要此回调的话置为null即可</param>
        /// <param name="udpateFileIndexCallback">正在更新的文件序号及收到的数据量的回调，如果序号等于文件总数则标志着更新结束且数据量处记录着新版本的版本号，如果不需要此回调的话置为null即可</param>
        public void Update(int clientVersion, UpdateInfoCallback updateInfoCallback, UpdateDataReachCallback updateDataReachCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.updateInfoCallback = updateInfoCallback;
            netCallback.updateDataReachCallback = updateDataReachCallback;
            netCallback.State = NetCallback.WaitUpdateInfo;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1030", clientVersion.ToString());
        }

        /// <summary>
        /// 向远程服务器发送登录请求
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        /// <returns>返回登录信息，null表示超时，数值表示登录成功并且代表着用户的权限等级，其他则是不成功并且说明了不成功的原因</returns>
        public string Login(string userName, string password)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1000", userName + "|" + password);
            netCallback.DataReach.WaitOne(3000);
            return (string)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向远程服务器发送登录请求
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        /// <param name="stringCallback">登录结果回调，null表示超时，数值表示登录成功并且代表着用户的权限等级，其他则是不成功并且说明了不成功的原因</param>
        public void Login(string userName, string password, StringCallback stringCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.stringCallback = stringCallback;
            netCallback.State = NetCallback.WaitString;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1000", userName + "|" + password);
        }

        /// <summary>
        /// 向服务器发送更改密码请求
        /// </summary>
        /// <param name="originalPassword">旧密码</param>
        /// <param name="newPassword">新密码</param>
        /// <returns>返回null表示超时，""表示成功，"……"表示失败及其原因</returns>
        public string ChangePassword(string originalPassword, string newPassword)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1010", originalPassword + "|" + newPassword);
            netCallback.DataReach.WaitOne(3000);
            return (string)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向服务器发送更改密码请求
        /// </summary>
        /// <param name="originalPassword">旧密码</param>
        /// <param name="newPassword">新密码</param>
        /// <param name="stringCallback">回调委托实例，null表示超时，""表示成功，"……"表示失败及其原因</param>
        public void ChangePassword(string originalPassword, string newPassword, StringCallback stringCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.stringCallback = stringCallback;
            netCallback.State = NetCallback.WaitString;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1010", originalPassword + "|" + newPassword);
        }

        /// <summary>
        /// 向远程服务器请求指定的DataSet
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>返回的DataSet</returns>
        public DataSet GetDataSet(string sql)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1040", sql);
            netCallback.DataReach.WaitOne(3000);
            return (DataSet)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向远程服务器请求指定的DataSet
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="dataSetCallback">DataSet到达后调用此委托</param>
        public void GetDataSet(string sql, DataSetCallback dataSetCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.dataSetCallback = dataSetCallback;
            netCallback.State = NetCallback.WaitDataSet;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1040", sql);
        }

        /// <summary>
        /// 向远程服务器请求指定的DataTable
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>返回DataTable</returns>
        public DataTable GetDataTable(string sql)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1050", sql);
            netCallback.DataReach.WaitOne(3000);
            return (DataTable)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向远程服务器请求指定的DataTable
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="dataTableCallback">DataTable到达后调用此委托</param>
        public void GetDataTable(string sql, DataTableCallback dataTableCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.dataTableCallback = dataTableCallback;
            netCallback.State = NetCallback.WaitDataTable;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1050", sql);
        }

        /// <summary>
        /// 向远程服务器请求执行指定的SQL语句
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns>null表示超时，其他表示受影响的行数</returns>
        public int ExecuteSql(string sql)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.DataReach = new ManualResetEvent(false);
            netCallback.State = NetCallback.Block;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1060", sql);
            netCallback.DataReach.WaitOne(3000);
            return (int)netCallback.AsyncObject;
        }

        /// <summary>
        /// 向远程服务器请求执行指定的SQL语句
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="intCallback">回调委托，null表示超时，其他表示受影响的行数</param>
        public void ExecuteSql(string sql, IntCallback intCallback)
        {
            NetCallback netCallback = new NetCallback();
            netCallback.intCallback = intCallback;
            netCallback.State = NetCallback.WaitInt;
            callbackMap[net.PackageIdentifier] = netCallback;
            net.ProcessSend("1060", sql);
        }
    }
}
